package co.china.lottery.account.service.impl;

import net.blogjava.frankiegao123.log.slf4j.Log;

import java.math.BigDecimal;
import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException;
import org.springframework.stereotype.Component;

import co.china.lottery.account.annotation.AccountPay;
import co.china.lottery.account.dao.PayAccountDao;
import co.china.lottery.account.dao.entity.LPayAccount;
import co.china.lottery.account.dao.entity.LPayAccountHis;
import co.china.lottery.account.exception.ServiceCode;
import co.china.lottery.account.exception.ServiceCodeException;
import co.china.lottery.account.service.AccountService;
import co.china.lottery.account.service.CreateAccountService;
import co.china.lottery.account.service.bean.AccountRequest;
import co.china.lottery.account.service.bean.AccountResponse;
import co.china.lottery.account.service.bean.AccountTransReq;
import co.china.lottery.account.service.bean.ResultCode;
import co.china.lottery.account.service.bean.TransferResponse;
import co.china.lottery.account.service.code.PayDecrementCode;
import co.china.lottery.account.service.code.PayIncrementCode;
import co.china.lottery.account.service.code.base.AccountCode;
import co.china.lottery.account.service.impl.base.AbstractAccountService;
import co.china.lottery.account.util.Tools;

/**
 * @ClassName PayAccountService
 * @Description pay
 * @author bati
 * @date 2014-9-8
 */
@Component
@AccountPay
public class PayAccountService extends AbstractAccountService implements AccountService {

	public PayAccountService(Log log) {
		super(log);
	}

	public PayAccountService() {
		super(log);
	}

	@Autowired
	private PayAccountDao payAccountDao;
	
	@Autowired
	@AccountPay
	private CreateAccountService createPayAccountService;

	//充值
	public AccountResponse increment(AccountRequest accountRequest) {
		
		boolean isIncrement = true;
		
		AccountCode code = forCode(accountRequest, isIncrement);
		
		if(code == null){
			throw new ServiceCodeException(ServiceCode.ACCOUNT_CODE_ERROR);
		}
		
		// 检查参数的有效性
		checkAndLog(accountRequest, code);

		//检查管理员参数的有效性
		checkAdminOperation(accountRequest, code);

		LPayAccount account = null;
		LPayAccountHis his = null;
		try {
			// 获取支付账户数据
			account = (LPayAccount) createPayAccountService.getOrCreateAccount(accountRequest.getUserId(),true);

			double money = Tools.isBlank(accountRequest.getMoney())?0.0:Double.valueOf(accountRequest.getMoney());
			long serviceId = Tools.isBlank(accountRequest.getServiceId())?0l:Long.valueOf(accountRequest.getServiceId());
			if (code.getCode().equals("1000")) {
				his = LPayAccountHis.getCommits(account, money,code, serviceId);
			}else{
				his = LPayAccountHis.getCommit(account, money,code, serviceId);
			}
			//更新备注及操作员
			setPayAccountHisData(his, accountRequest);
			 double payBalance =  this.agentAccountQuery(accountRequest.getUserId());
			 his.setBalanceBefore(payBalance);
			 his.setBalanceAfter(Tools.add(payBalance, his.getDebitCredit()));
			payAccountDao.save(his);

			log.info("increment pay his success::{}",his);
			
		}catch (ServiceCodeException e) {
			log.error("increment pay accountServiceCodeException  exception :{} ",e.getMessage());
			return ResultCode.create(AccountResponse.class,e.getCode());
		}catch (HibernateOptimisticLockingFailureException e){
			log.error("increment pay hibernate commit  exception :{} ",e.getMessage());
			return ResultCode.create(AccountResponse.class,ServiceCode.CONCURRENT_OPERATE_FAILED);
		}catch (Exception e) {
			log.error("increment pay other exception :{} ", e.getMessage());
			return ResultCode.create(AccountResponse.class,ServiceCode.UNKNOW_SYSTEM_ERROR);
		}
		return toAccountResponse(account,his);
	}

	public  AccountResponse decrement(AccountRequest accountRequest) {
		boolean isIncrement = false;
		String method = (isIncrement ? "increment" : "decrement");
		AccountCode code = forCode(accountRequest, isIncrement);
		if(code == null) {
			log.error("{}, cannot find register {}, code: {}", method,isIncrement ? "PayIncrementCode" : "PayDecrementCode",accountRequest.getAccountCode());
			throw new ServiceCodeException(ServiceCode.ACCOUNT_CODE_ERROR);
		}
		// 检查参数的有效性
		checkAndLog(accountRequest, code);
		// 检查管理员参数的有效性
		checkAdminOperation(accountRequest, code);

		LPayAccount account = null;
		LPayAccountHis his = null;
		try {
			// 获取支付账户数据
			account = (LPayAccount) createPayAccountService.getOrCreateAccount(accountRequest.getUserId(),true);

			synchronized(this){
			    	double balance = payAccountDao.unCommitHis2(account.getAgentId(),Tools.getPreDate2(new Date()));
					balance = account.getBalance()+balance;
					if(isOverdraft(balance, accountRequest, isIncrement)){
						return createOverdraft(accountRequest,balance);
					}
					double moeny = Double.valueOf(accountRequest.getMoney());
					long serviceId = Tools.isBlank(accountRequest.getServiceId())?0l:Long.valueOf(accountRequest.getServiceId());
					
					his = LPayAccountHis.getCommit(account, moeny,code, serviceId);
					setPayAccountHisData(his, accountRequest);
					his.setBalanceBefore(balance);
					his.setBalanceAfter(Tools.add(balance, his.getDebitCredit()));
					payAccountDao.save(his);
			}

			log.info("decrement his success::{}",his);
		}catch (ServiceCodeException e) {
			log.error("decrement pay accountServiceCodeException  exception :{} ",e.getMessage());
			return ResultCode.create(AccountResponse.class,e.getCode());
		}catch (HibernateOptimisticLockingFailureException e) {
			log.error("decrement pay hibernate commit  exception :{} ",e.getMessage());
			return ResultCode.create(AccountResponse.class,ServiceCode.CONCURRENT_OPERATE_FAILED);
		}catch (Exception e){
			log.error("decrement pay  other exception :{} ", e.getMessage());
			return ResultCode.create(AccountResponse.class,ServiceCode.UNKNOW_SYSTEM_ERROR);
		}
		return toAccountResponse(account,his);
	}
	

	/**
	 * 设置支付账户历史数据
	 */
	public void setPayAccountHisData(LPayAccountHis his,AccountRequest accountRequest){
		if(!Tools.isBlank(accountRequest.getCreateUser())){
			his.setCreateUser(accountRequest.getCreateUser());
		}
		if(!Tools.isBlank(accountRequest.getRemark())){
			his.setRemark(accountRequest.getRemark());
		}
	}
	
	/*private AccountResponse createOverdraft(AccountRequest accountRequest,double balance) {
		AccountResponse resp = ResultCode.create(AccountResponse.class,ServiceCode.BALANCE_NOT_ENOUGH);
		resp.setBalance(String.valueOf(balance));
		resp.setMoney(accountRequest.getMoney());
		resp.setUserId(accountRequest.getUserId());
		return resp;
	}*/

	public AccountResponse toAccountResponse(LPayAccount account,LPayAccountHis his) {
		AccountResponse response = ResultCode.createSuccess(AccountResponse.class);
		response.setAccountHisId(his.getId());
		response.setBalance(String.valueOf(his.getBalanceAfter()));
		response.setMoney(String.valueOf(his.getDebitCredit()));
		response.setProcessTime(Tools.getTimestamptoString(his.getCreateTime()) );
		response.setUserId(account.getAgentId());
		return response;
	}

	public double agentAccountQuery(String agentId){
		LPayAccount account = (LPayAccount) createPayAccountService.getOrCreateAccount(agentId,true);
		double balance = payAccountDao.unCommitHis(agentId);
		balance = account.getBalance()+balance;
		return balance;
	}
	
	public BigDecimal newAgentAccountQuery(String agentId){
		LPayAccount account = (LPayAccount) createPayAccountService.getOrCreateAccount(agentId,true);
		double balance = payAccountDao.unCommitHis(agentId);
		BigDecimal money = new BigDecimal(account.getBalance()+balance);
		money=money.setScale(2,BigDecimal.ROUND_HALF_UP);
		return money;
	}
	
	protected AccountCode forCode(AccountRequest accountRequest,boolean isIncrement) {
		if(isIncrement) {
			return PayIncrementCode.forCode(accountRequest.getAccountCode());
		}
		return PayDecrementCode.forCode(accountRequest.getAccountCode());
	}

	public TransferResponse transfer(AccountTransReq req){
		return null;
	}

	@Override
	public AccountResponse prizeBatchSubmit(AccountRequest req) {
		return null;
	}
}